Stata:调用百度文心千帆大模型进行文本分析与文本主要内容提取 —— 银保监行政处罚决定书文本提取
为了让大家更好的理解本文的内容,欢迎各位培训班会员参加明晚 8 点的直播课 「Stata:调用百度文心千帆大模型进行文本分析与文本主要内容提取 —— 银保监行政处罚决定书文本提取」
今年年初给大家分享过一份 银保监本级、分局本级、机关行政处罚信息数据(截止 2023 年 2 月 13 日) 数据。实际上这些行政处罚信息包含多种形式的,大体上是处罚决定书和处罚信息公开表,由于处罚决定书的内容比较混乱,难以整理成表格数据,所以就没有整理。
百度文心一言最近开放了 API 接口,于是我就想是不是可以调用文心一言的 API 接口自动处理这些处罚决定书文本来提取主要信息。
申请文心千帆大模型内测
首先我们需要申请文心千帆大模型内测的资格,网址是这个:https://cloud.baidu.com/product/wenxinworkshop?track=ae35a3396ecb3afe68e19773b574a198b11ace12bfeed89c
然后在文心千帆控制台创建应用:https://console.bce.baidu.com/ai/#/ai/wenxinworkshop/overview/index
由于本课程讲解的 ERNIE-Bot 模型的调用是需要付费的,所以可以先给自己的账户充点钱,10 块钱即可。
价格如下,调用一次的价格差不多 1 分钱左右:
创建应用后可以应用列表中可以看到自己的 API Key 和 Secret Key:https://console.bce.baidu.com/ai/#/ai/wenxinworkshop/app/list,注意保存好。
大家注意把课程代码中的 API key 和 Secret Key 替换成自己的。
最后再阅读 API 使用文档即可使用了:https://cloud.baidu.com/doc/WENXINWORKSHOP/s/jlil56u11 。本课程中将以 ERNIE-Bot 的使用为例进行讲解。
银保监处罚决定书关键信息提取
附件中我准备了一些 doc 格式的 word 文档,是银保监处罚决定书,例如 1091075.doc
文件:
我们的目标是从中提取如下变量:
年份 标题 处罚决定书文号 主要违法违规事实或案由 处罚依据 处罚决定 作出处罚决定的机关名称 作出处罚决定的日期 被处罚个人姓名 被处罚单位名称 被处罚单位的法定代表人或主要负责人姓名 发布时间
因为提供的示例数据是 doc 文件,Stata 无法处理,所以我们首先使用 R 语言的 textreadr 包进行读取转换:
# 安装 textreadr 包
# install.packages("pacman")
# pacman::p_load_gh("trinker/textreadr")
library(textreadr)
read_dir("doc") -> docdf
library(tidyverse)
docdf %>%
as_tibble() %>%
mutate(content = str_squish(content),
length = str_length(content)) %>%
arrange(desc(length)) -> docdf
# 保存
docdf %>%
haven::write_dta("docdf.dta")
不过有些 doc 文件似乎有问题,无法处理。我们把这些文件筛选出来,下面就完全使用 Stata 了。
首先提取所有的文件名:
*- 创建 errordoc 文件夹
cap mkdir "errordoc"
local files: dir "doc" files "*.doc"
local n: word count `files'
clear
set obs `n'
gen document = ""
forval i = 1/`=_N' {
local file: word `i' of `files'
replace document = `"`file'"' in `i'
}
replace document = subinstr(document, ".doc", "", .)
save "alldocuments", replace
读取成功的文件存放在 docdf.dta 文件夹中,和 alldocuments merge 起来即可筛选出读取失败的:
use docdf, clear
merge 1:1 document using alldocuments
keep if _m == 2
*- 循环把这些文件 copy 到 errordoc 里面
forval i = 1/`=_N' {
copy "doc/`=document[`i']'.doc" "errordoc/`=document[`i']'.doc", replace
}
这些文件可以使用 word 打开,另存为 doc 文件再放回到 doc 文件夹中。然后再重复最初的 R 代码即可。这里因为时间关系,我就不再手动一个个操作了。
use docdf, clear
*- 由于文心千帆模型的参数长度限制,这里长度超过 2000 的(加上其他的文本,差不多不能超过 1800)不能一次解析,可以手动缩短后再解析。
*- 这里我们选择 10 条为例进行解析
drop if length >= 1800
keep in 1/10
可以把这 10 个文件单独拿出来方便等下比对:
cap mkdir "usedoc"
forval i = 1/`=_N' {
copy "doc/`=document[`i']'.doc" "usedoc/`=document[`i']'.doc", replace
}
save usedocdf, replace
ERNIE-Bot 模型接口的使用
首先创建一个对话:
curl 不是 Stata 自带的命令,而是一个 DOS/Shell 命令,Win10 之后的系统或者 Mac 系统都可以直接使用,旧版本的 Windows 系统需要自行安装,具体可以百度搜索下教程。
*- 注意这里需要使用自己的 API key 和 Secret key
!curl 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=PVodUnhWFKaORmyBHVGFuwZK&client_secret=ysmvX70jAKPABxg5bEeSEABZyBGAfjIx' -o session.json
运行上面的代码后,进程信息会被保存到 session.json 文件里面,下面我们使用 insheetjson 处理提取:
*- 使用 insheetjson 处理这个 json 文件,提取 access_token
*- 查看响应
insheetjson using session.json, showr flatten
*> Response from server:
*> refresh_token = 25.2bb9649d828da2337a74e797c24fac66.315360000.2005638177.282335-36641548
*> expires_in = 2592000
*> session_key = 9mzdWuuW5A+0pBOuEtucUaqszV9TUlL916McJ7f7h6fUBLUH7O+9lTi\/cGZoMW6xLnu5jZqPp58xHIuLBp5REXAxz
*> > PQIhg==
*> access_token = 24.a77d6a26c0f1846bb616530931a1077e.2592000.1692870177.282335-36641548
*> scope = public brain_all_scope easydl_mgr easydl_retail_mgr ai_custom_retail_image_stitch ai_custom_test
*> > _oversea easydl_pro_job easydl_pro_mgr ai_custom_yiyan_com ai_custom_yiyan_com_eb_instant wenxinworkshop_mgr a
*> > i_custom_yiyan_com_bloomz7b1 ai_custom_yiyan_com_emb_text wise_adapt lebo_resource_base lightservice_public he
*> > tu_basic lightcms_map_poi kaidian_kaidian ApsMisTest_Test\u6743\u9650 vis-classify_flower lpq_\u5f00\u653e cop
*> > _helloScope ApsMis_fangdi_permission smartapp_snsapi_base smartapp_mapp_dev_manage iop_autocar oauth_tp_app sm
*> > artapp_smart_game_openapi oauth_sessionkey smartapp_swanid_verify smartapp_opensource_openapi smartapp_opensou
*> > rce_recapi fake_face_detect_\u5f00\u653eScope vis-ocr_\u865a\u62df\u4eba\u7269\u52a9\u7406 idl-video_\u865a\u6
*> > 2df\u4eba\u7269\u52a9\u7406 smartapp_component smartapp_search_plugin avatar_video_test b2b_tp_openapi b2b_tp_
*> > openapi_online smartapp_gov_aladin_to_xcx
*> session_secret = 0da8132cd827743b94d1a8b827d98a44
access_token 就是我们想要提取的对话 id,相当于我们创建了一个聊天室。
*- 使用 insheetjson 处理这个 json 文件,提取 access_token
*- 查看响应
insheetjson using session.json, showr flatten
clear all
gen str100 access_token = ""
insheetjson access_token using session.json, column("access_token")
compress
local access_token = "`=access_token[1]'"
di "`access_token'"
*> 24.a77d6a26c0f1846bb616530931a1077e.2592000.1692870177.282335-36641548
然后就可以循环提问、保存结果了:
use usedocdf, clear
*- 去除所有的双引号
replace content = subinstr(content, `"""', "", .)
*- 循环提问、保存结果
cap mkdir "json"
forval i = 1/10 {
*- 发起提问
!curl -XPOST 'https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token=`access_token'' -d '{"messages": [{"role":"user","content":"阅读这段话:\"`=content[`i']'\",提取年份、标题、处罚决定书文号、主要违法违规事实或案由、处罚依据、处罚决定、作出处罚决定的机关名称、作出处罚决定的日期、被处罚个人姓名、被处罚单位名称、被处罚单位的法定代表人或主要负责人姓名 、发布时间、罚款金额信息。结果使用文本表示,用数字对结果进行编号"}]}' -o json/`=document[`i']'.json
}
为了便于处理,所有的提问我都采取这种格式:
阅读这段话:"......",提取年份、标题、处罚决定书文号、主要违法违规事实或案由、处罚依据、处罚决定、作出处罚决定的机关名称、作出处罚决定的日期、被处罚个人姓名、被处罚单位名称、被处罚单位的法定代表人或主要负责人姓名 、发布时间、罚款金额信息。结果使用文本表示,用数字对结果进行编号
经过多次测试,这样得到的结果会很容易处理。
然后再循环解析得到的 json 文件,提取 result 结果,首先测试一个:
*- 提取结果
insheetjson using json/1055966.json, showr flatten
*> Response from server:
*> id = as-uj5e4nkn5d
*> object = chat.completion
*> created = 1690220163
*> result = 1. 年份:2022\n2. 标题:合众人寿保险股份有限公司山西分公司违法违规案\n3. 处罚决定书文号:晋银保
*> > 监罚决字〔2022〕31号\n4. 主要违法违规事实或案由:\n\n\n| 序号 | 违法违规事实 |\n| --- | --- |\n| 1 | 编制虚假
*> > 财务资料 |\n| 2 | 给予投保人、被保险人保险合同约定以外其他利益 |\n| 3 | 欺骗投保人、被保险人 |\n\n5. 处罚依据
*> > :\n\n\n\t* 《中华人民共和国保险法》第八十六条\n\t* 《中华人民共和国保险法》第一百一十六条\n\t* 《中华人民共和
*> > 国保险法》第一百六十一条\n6. 处罚决定:\n\n\n\t* 对合众人寿山西分公司责令改正,处15万元罚款\n\t* 对合众人寿山
*> > 西分公司责令改正,处5万元罚款\n\t* 对合众人寿山西分公司责令改正,处5万元罚款\n7. 作出处罚决定的机关名称:中国
*> > 银保监会山西监管局\n8. 作出处罚决定的日期:2022年6月8日\n9. 被处罚个人姓名:无\n10. 被处罚单位名称:合众人寿保
*> > 险股份有限公司山西分公司\n11. 被处罚单位的法定代表人或主要负责人姓名:郑江龙\n12. 发布时间:2022年6月8日\n13.
*> > 罚款金额:25万元
*> is_truncated = false
*> need_clear_history = false
*> usage:prompt_tokens = 1549
*> usage:completion_tokens = 370
*> usage:total_tokens = 1919
循环处理所有文件:
use usedocdf, clear
gen str2000 result = ""
forval i = 1/`=_N' {
insheetjson result using json/`=document[`i']'.json, column(result) replace offset(`=`i'-1')
}
format result %10s
再从 result 中提取我们想要的字段即可:
*- 处理结果
gen 年份 = ustrregexs(1) if ustrregexm(result, "1\. 年份:(.*)\\n2\.")
gen 标题 = ustrregexs(1) if ustrregexm(result, "2\. 标题:(.*)\\n3\.")
gen 处罚决定书文号 = ustrregexs(1) if ustrregexm(result, "3\. 处罚决定书文号:(.*)\\n4\.")
gen 主要违法违规事实或案由 = ustrregexs(1) if ustrregexm(result, "4\. 主要违法违规事实或案由:(.*)\\n5\.")
gen 处罚依据 = ustrregexs(1) if ustrregexm(result, "5\. 处罚依据:(.*)\\n6\.")
gen 处罚决定 = ustrregexs(1) if ustrregexm(result, "6\. 处罚决定:(.*)\\n7\.")
gen 作出处罚决定的机关名称 = ustrregexs(1) if ustrregexm(result, "7\. 作出处罚决定的机关名称:(.*)\\n8\.")
gen 作出处罚决定的日期 = ustrregexs(1) if ustrregexm(result, "8\. 作出处罚决定的日期:(.*)\\n9\.")
gen 被处罚个人姓名 = ustrregexs(1) if ustrregexm(result, "9\. 被处罚个人姓名:(.*)\\n10\.")
gen 被处罚单位名称 = ustrregexs(1) if ustrregexm(result, "10\. 被处罚单位名称:(.*)\\n11\.")
gen 被处罚单位的法定代表人或主要负责人姓名 = ustrregexs(1) if ustrregexm(result, "11\. 被处罚单位的法定代表人或主要负责人姓名:(.*)\\n12\.")
gen 发布时间 = ustrregexs(1) if ustrregexm(result, "12\. 发布时间:(.*)\\n13\.")
gen 罚款金额 = ustrregexs(1) if ustrregexm(result, "13\. 罚款金额:(.*)")
compress
foreach i of varlist _all {
cap format `i' %10s
cap replace `i' = subinstr(`i', "\n", "", .)
cap replace `i' = subinstr(`i', "\t", "", .)
}
drop result length
replace 年份 = subinstr(年份, "年", "", .)
destring 年份, replace
save "处理结果", replace
看起来效果还挺不错!
应用这个技术就可以快速处理文本数据并提取关键变量了!不过缺点就是只能一次处理 2000 字内的文本。或许对于长文本可以通过预先切分、分多次提取。
直播信息
为了让大家更好的理解上面的内容,欢迎各位培训班会员参加明晚 8 点的直播课 「Stata:调用百度文心千帆大模型进行文本分析与文本主要内容提取」
直播地址:腾讯会议(需要报名 RStata 培训班参加) 讲义材料:需要报名 RStata 培训班,详情可阅读:一起来学习 R 语言和 Stata 啦!学习过程中遇到的问题也可以随时提问!
更多关于 RStata 会员的更多信息可添加微信号 r_stata 咨询:
附件下载(点击文末的阅读原文即可跳转):
https://rstata.duanshu.com/#/brief/course/6aac8b39269d431eaa9017b25a966463